﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Projektarbete
{
    /// <summary>
    /// Creates a new inventory for a player
    /// </summary>
    class Inventory
    {
        //TODO: RemoveItemWithNotification
        public enum SortOptions { Name, Price, Weight, Size };

        float maxWeight;
        public float getMaxWeight { get { return maxWeight; } }
        float maxSize;
        public float getMaxSize { get { return maxSize; } }

        float currentWeight;
        public float getCurrentWeight { get { return currentWeight; } }
        float currentSize;
        public float getCurrentSize { get { return currentSize; } }


        LinkedList<Item> contents;
        public LinkedList<Item> GetContentsAsLinkedList { get { return contents; } }
        public Item[] GetContentsAsArray { get { return contents.ToArray(); } }

        /// <summary>
        /// Creates a new backpack
        /// </summary>
        /// <param name="maxWeight">The maximum weight this backpack can contain</param>
        /// <param name="maxSize">The maximum size this backpack can contain</param>
        public Inventory(float maxWeight, float maxSize)
        {
            this.maxWeight = maxWeight;
            this.maxSize = maxSize;

            currentWeight = 0.0f;
            currentSize = 0.0f;

            contents = new LinkedList<Item>();
        }

        /// <summary>
        /// Checks if the bag contains an item
        /// </summary>
        /// <param name="item">Item to check</param>
        /// <returns></returns>
        public bool Contains(Item item)
        {
            return contents.Contains(item);
        }

        /// <summary>
        /// Checks if the bag contains an item
        /// </summary>
        /// <param name="item">Item to check</param>
        /// <param name="amount">Amount</param>
        /// <returns>Horses</returns>
        public bool Contains(Item item, int amount)
        {
            int count = 0;
            foreach (Item currentItem in contents)
            {
                if (currentItem.Equals(item))
                    count++;
            }

            return count >= amount;
        }

        /// <summary>
        /// Adds an item to the backpack if it doesn't exceed the max weight/size. Return true if sucessfully added. Does not display any notification
        /// </summary>
        /// <param name="item">Item to add</param>
        /// <returns>If sucessfully added</returns>
        public bool AddItem(Item item)
        {
            if (currentSize + item.getSize <= maxSize &&
                currentWeight + item.getWeight <= maxWeight)
            {
                contents.AddLast(item);
                UpdateBackpack();
                HUD.AddNotification(new Notification(item.getName + " added to inventory", NotificationColor.AddItem, NotificationLifetime.AddItem));
                return true;
            }
            else
            {
                if (currentSize + item.getSize > maxSize && currentWeight + item.getWeight > maxSize)
                {
                    HUD.AddNotification(new Notification("You need to free up both room and weight for that to work", NotificationColor.Info, NotificationLifetime.Info));
                }
                else if (currentSize + item.getSize > maxSize)
                {
                    HUD.AddNotification(new Notification("You need more room in your inventory to fit it in there", NotificationColor.Info, NotificationLifetime.Info));
                }
                else
                {
                    HUD.AddNotification(new Notification("You can't carry that much, drop some weight", NotificationColor.Info, NotificationLifetime.Info));
                }
            }

            return false;
        }

        /// <summary>
        /// Adds an item to the backpack if it doesn't exceed the max weight/size. Return true if sucessfully added. Does not display any notification
        /// </summary>
        /// <param name="item">Item to add</param>
        /// <returns>If sucessfully added</returns>
        public bool AddItemDiscreetly(Item item)
        {
            //TODO: Overencumbebereded effect

            if (currentSize + item.getSize <= maxSize)
            {
                //if(currentWeight + item.getWeight > maxWeight)
                //Adddebuff. Or something
                contents.AddLast(item);
                UpdateBackpack();
                return true;
            }
            else
                return false;
        }

        /// <summary>
        /// Removes a single item from the backpack
        /// </summary>
        /// <param name="item">Item to remove</param>
        public void RemoveItem(Item item)
        {
            if (contents.Contains(item))
            {
                contents.Remove(item);
                UpdateBackpack();
                HUD.AddNotification(new Notification(item.getName + " removed from inventory", NotificationColor.RemoveItem, NotificationLifetime.RemoveItem));
            }
        }

        public void RemoveItemDiscreetly(Item item)
        {
            if (contents.Contains(item))
            {
                contents.Remove(item);
                UpdateBackpack();
            }
        }

        /// <summary>
        /// Removes an (or more) items from the backpack
        /// </summary>
        /// <param name="item">Item to remove</param>
        /// <param name="amount">Amount to remove</param>
        public void RemoveItem(Item item, int amount)
        {
            int available = 0;

            foreach (Item currentItem in contents)
                if (currentItem.Equals(item))
                    available++;


            if (available >= amount)
                for (int x = 0; x < amount; x++)
                    contents.Remove(item);

            UpdateBackpack();
            HUD.AddNotification(new Notification(available + " " + item.getName + " removed from inventory", NotificationColor.RemoveItem, NotificationLifetime.RemoveItem));
        }

        /// <summary>
        /// Removes every instance of the selected item from the backpack
        /// </summary>
        /// <param name="item">Item to remove</param>
        public void RemoveAllOfItem(Item item)
        {
            int available = 0;

            foreach (Item currentItem in contents)
                if (currentItem.Equals(item))
                    available++;

            for (int x = 0; x < available; x++)
                contents.Remove(item);

            UpdateBackpack();
            HUD.AddNotification(new Notification(available + " " + item.getName + " removed from inventory", NotificationColor.RemoveItem, NotificationLifetime.RemoveItem));
        }

        /// <summary>
        /// Update the current waight and size of the backpack
        /// </summary>
        public void UpdateBackpack()
        {
            currentSize = 0.0f;
            currentWeight = 0.0f;

            foreach (Item currentItem in contents)
            {
                currentSize += currentItem.getSize;
                currentWeight += currentItem.getWeight;
            }
        }

        /// <summary>
        /// Sorts the backpack
        /// </summary>
        /// <param name="sortOption">Backpack.SortOptions</param>
        public void SortBackpack(SortOptions sortOption)
        {
            //Skapa en temporär lista för att sortera
            List<Item> tempList = contents.ToList();

            contents = new LinkedList<Item>();

            switch (sortOption)
            {
                case SortOptions.Name:
                    var listName = from element in tempList
                                   orderby element.getName
                                   select element;

                    foreach (Item item in listName)
                        contents.AddLast(item);
                    break;
                case SortOptions.Price:
                    var listPrice = from element in tempList
                                    orderby element.getValue
                                    select element;

                    foreach (Item item in listPrice)
                        contents.AddLast(item);
                    break;
                case SortOptions.Size:
                    var listSize = from element in tempList
                                   orderby element.getSize
                                   select element;

                    foreach (Item item in listSize)
                        contents.AddLast(item);
                    break;
                case SortOptions.Weight:
                    var listWeight = from element in tempList
                                     orderby element.getWeight
                                     select element;

                    foreach (Item item in listWeight)
                        contents.AddLast(item);
                    break;
            }
        }
    }
}
